Implement models to compute infiltration rate
!! Implement models to compute infiltration rate !|author: <a href="mailto:giovanni.ravazzani@polimi.it">Giovanni Ravazzani</a> ! license: <a href="http://www.gnu.org/licenses/">GPL</a> ! !### History ! ! current version 1.1 - 16th June 2016 ! ! | version | date | comment | ! |----------|-------------|----------| ! | 1.0 | 28/May/2014 | Original code | ! | 1.1 | 16/Jun/2016 | added CurveNumber function | ! !### License ! license: GNU GPL <http://www.gnu.org/licenses/> ! !### Module Description ! Implement models to compute infiltration rate: ! ! * [[Philip(function)]] model ! ! * [[GreenAmpt(function)]] model ! ! * [[SCScurveNumber(function)]] model ! MODULE Infiltration USE DataTypeSizes, ONLY : & ! Imported Type Definitions: short, float, double USE LogLib,ONLY : & ! imported routines: Catch USE IniLib, ONLY : & !Imported types: IniList, & !Imported routines: IniOpen, IniClose , & IniReadInt, IniReadReal , & KeyIsPresent, IniReadString, & IniReadDouble, SectionIsPresent USE GridLib, ONLY : & !imported definitions: grid_real, grid_integer, & !imported routines: NewGrid USE StringManipulation, ONLY: & !Imported routines: ToString USE GridOperations, ONLY : & !imported routines: GridByIni, CRSisEqual !, CellArea, & !Imported assignment: !ASSIGNMENT (=) USE SoilProperties, ONLY : & !Imported definitions: SoilType USE DomainProperties, ONLY : & !imported variables: mask USE Richards, ONLY : & !imported routines: SetRichardsBC, SolveRichardsBC, & !imported variables: nsteps, parameters, cell, & dx, S, h0grid, drncum, & infilcum, evapcum, runoffcum IMPLICIT NONE ! Global (i.e. public) Declarations: INTEGER (KIND = short) :: infiltrationModel !infiltration model labels INTEGER (KIND = short), PARAMETER :: SCS_CN = 1 !!Soil Conservation Service Curve Number INTEGER (KIND = short), PARAMETER :: PHILIPEQ = 2 !!Philip's equation INTEGER (KIND = short), PARAMETER :: GREEN_AMPT = 3 !!Green Ampt INTEGER (KIND = short), PARAMETER :: ROSS_BC = 4 !!Richards equations solution by Ross with Broooks and Corey SWRC INTEGER (KIND = short), PARAMETER :: ROSS_VG = 5 !!Richards equations solution by Ross with Van Genuchten SWRC !soil TYPE (SoilType), PRIVATE, ALLOCATABLE :: soils (:) INTEGER (KIND = short) :: soilDivisions !! number of subdivisions of soil layer !common properties TYPE (grid_integer), PRIVATE :: soilTypeMap !read in subroutine SetParametersFromDB TYPE (grid_real), PUBLIC :: ksat !!saturated hydraulic conductivity [m/s] TYPE (grid_real), PUBLIC :: thetar !!residual water content [m3/m3] TYPE (grid_real), PUBLIC :: thetas !!saturated water content [m3/m3] TYPE (grid_real), PUBLIC :: psdi !!pore size distribution index by Brooks and Corey [-] TYPE (grid_real), PUBLIC :: wiltingPoint !!wilting point [m3/m3] TYPE (grid_real), PUBLIC :: fieldCapacity !!field capacity [m3/m3] TYPE (grid_real), PRIVATE :: smax !!maximum soil storage [m] DEBUG non so chi usa questo parametro !used by PHILIPS, ROSS_BC and ROSS_VG TYPE (grid_real), PUBLIC :: psic !!bubbling pressure, air entry value [m] !used by SCS_CN TYPE (grid_real), PUBLIC :: curveNumber !! curve number [-] TYPE (grid_real), PUBLIC :: abstractionRatio !! initial abstraction ratio of the SCS-CN [-] default = 0.2 TYPE (grid_real), PUBLIC :: storativity !! storativity of the SCS-CN [mm], default = 254 TYPE (grid_real), PUBLIC :: sEff !! effective soil retention capacity [mm] TYPE (grid_real), PUBLIC :: raincum !!cumulated gross rainfall [mm] !used by GREEN_AMPT TYPE (grid_real), PUBLIC :: phy !!wetting front soil suction head [m] !used by ROSS_VG TYPE (grid_real), PRIVATE :: ptort !!tortuosity index [-] TYPE (grid_real), PRIVATE :: nvg !!n shape parameter for Van Genuchten SWRC [-] TYPE (grid_real), PRIVATE :: mvg !!m shape parameter for Van Genuchten SWRC [-] TYPE (grid_real), PRIVATE :: ksatMatrix !!saturated conductivity of soil "matrix", !different from ksat when macropores impact. !Implemented only when vG WRC is used !used by PHILIPEQ and GREEN_AMPT TYPE (grid_real), PUBLIC :: cuminf !!cumulative infiltration [m] TYPE (grid_real), PUBLIC :: ism !!soil moisture at the beginning of storm event [m3/m3] !private declarations: INTEGER (KIND = short), PRIVATE :: parameterAssigningMethod !!1 = read each parameter from single file; 2 = assign parameter from soil type map INTEGER (KIND = short), PRIVATE, PARAMETER :: FROM_FILES = 1 INTEGER (KIND = short), PRIVATE, PARAMETER :: FROM_DB = 2 !public routines: PUBLIC :: InfiltrationInit PUBLIC :: Philip PUBLIC :: GreenAmpt PUBLIC :: SCScurveNumber PUBLIC :: Sat2scn !private routines: PRIVATE :: ReadSoilTypes PRIVATE :: SetParametersFromDB PRIVATE :: SetParametersFromFile !======= CONTAINS !======= ! Define procedures contained in this module. !============================================================================== !| Description: ! Initialize evapotranspiration computation SUBROUTINE InfiltrationInit & ! ( inifile, soilMoisture, soilDepth ) IMPLICIT NONE !Arguments with intent(in): CHARACTER (LEN = *), INTENT(IN) :: inifile TYPE (grid_real), INTENT (IN) :: soilMoisture TYPE (grid_real), INTENT (IN) :: soilDepth !local declarations: TYPE (IniList) :: infiltini !--------------------------------------end of declarations--------------------- !open and read configuration file CALL IniOpen (inifile, infiltini) !read infiltration model infiltrationModel = IniReadInt ('model', infiltini) !read number of subdivisions of soil layer soilDivisions = IniReadInt ('ross-divisions', infiltini) !check soil division and infiltration model IF (soilDivisions > 1 .AND. infiltrationModel == SCS_CN .OR. & soilDivisions > 1 .AND. infiltrationModel == PHILIPEQ .OR. & soilDivisions > 1 .AND. infiltrationModel == GREEN_AMPT ) THEN CALL Catch ('warning', 'Infiltration', & 'Infiltration model requires one subdivision of soil layer, divisions forced to 1') soilDivisions = 1 END IF !read parameter assigning method parameterAssigningMethod = IniReadInt ('parameter-assigning-method', infiltini) IF (parameterAssigningMethod == FROM_DB) THEN !check if all necessary info are defined IF (.NOT. KeyIsPresent ('soil-types-file', infiltini) ) THEN CALL Catch ('error', 'Infiltration', & 'missing ''soil-types-file'' keyword in configuration file') END IF IF (.NOT. SectionIsPresent ('soil-type-map', infiltini) ) THEN CALL Catch ('error', 'Infiltration', & 'missing ''soil-type-map'' section in configuration file') END IF !set parameter maps CALL SetParametersFromDB (infiltini, infiltrationModel) ELSE CALL SetParametersFromFile (infiltini, infiltrationModel) END IF !used by Philip model IF (infiltrationModel == PHILIPEQ .OR. & infiltrationModel == GREEN_AMPT ) THEN CALL NewGrid (cuminf, mask, 0.) CALL NewGrid (ism, mask, 0.) END IF !used by SCS-CN IF (infiltrationModel == SCS_CN) THEN CALL NewGrid (raincum, mask, 0.) END IF !when Richards equation solution is required, initialize Ross'parameters IF (infiltrationModel == ROSS_BC) THEN CALL SetRichardsBC (mask, ksat, thetas, thetar, psdi, psic, & soilDepth, soilMoisture, infiltini, soilDivisions) END IF ! Configuration terminated. Deallocate ini database CALL IniClose (infiltini) RETURN END SUBROUTINE InfiltrationInit !============================================================================== !| Description: ! read soil types from external file SUBROUTINE ReadSoilTypes & ! (inifile) IMPLICIT NONE !Arguments with intent(in): CHARACTER (LEN = *), INTENT(IN) :: inifile !!stores configuration information !local declarations TYPE(IniList) :: soilDB INTEGER (KIND = short) :: nsoils !number of soil types to read INTEGER (KIND = short) :: i !------------end of declaration------------------------------------------------ !open and read soil types file CALL IniOpen (inifile, soilDB) !get number of soil types to read IF (KeyIsPresent ('soil-types', soilDB) ) THEN !mandatory key nsoils = IniReadInt ('soil-types', soilDB) ELSE CALL Catch ('error', 'SoilBalance', & 'missing ''soil-types'' section in soil types file') END IF !allocate memory and read data ALLOCATE (soils(nsoils)) DO i = 1, nsoils soils (i) % ksat = IniReadDouble ('ksat', soilDB, section = ToString(i)) soils (i) % thetas = IniReadDouble ('thetas', soilDB, section = ToString(i)) soils (i) % thetar = IniReadDouble ('thetar', soilDB, section = ToString(i)) soils (i) % wp = IniReadDouble ('wp', soilDB, section = ToString(i)) soils (i) % fc = IniReadDouble ('fc', soilDB, section = ToString(i)) soils (i) % psic = IniReadDouble ('psic', soilDB, section = ToString(i)) soils (i) % psdi = IniReadDouble ('psdi', soilDB, section = ToString(i)) soils (i) % phy = IniReadDouble ('phy', soilDB, section = ToString(i)) soils (i) % smax = IniReadDouble ('smax', soilDB, section = ToString(i)) soils (i) % m = IniReadDouble ('m', soilDB, section = ToString(i)) soils (i) % n = IniReadDouble ('n', soilDB, section = ToString(i)) soils (i) % pp = IniReadDouble ('p', soilDB, section = ToString(i)) soils (i) % kx = IniReadDouble ('ksat-matrix', soilDB, section = ToString(i)) soils (i) % c = IniReadDouble ('c', soilDB, section = ToString(i)) soils (i) % s0 = IniReadDouble ('s0', soilDB, section = ToString(i)) soils (i) % cn = IniReadDouble ('cn', soilDB, section = ToString(i)) END DO !deallocate soilDB CALL IniClose (soilDB) RETURN END SUBROUTINE ReadSoilTypes !============================================================================== !| Description: ! set parameter maps from soil database SUBROUTINE SetParametersFromDB & ! (iniDB, model) IMPLICIT NONE ! Arguments with intent(in): TYPE (IniList), INTENT(IN) :: iniDB INTEGER (KIND = short), INTENT(IN) :: model !infiltration model !Local declaration: CHARACTER (LEN = 1000) :: soilTypeFile INTEGER (KIND = short) ::i, j, id !------------end of declaration------------------------------------------------ CALL Catch ('info', 'SoilBalance: ', 'setting soil parameters from database: ', & argument = IniReadString('soil-types-file', iniDB) ) !load soil types soilTypeFile = IniReadString('soil-types-file', iniDB) CALL ReadSoilTypes (soilTypeFile) ! load soil type map CALL GridByIni (iniDB, soilTypeMap, section = 'soil-type-map') !Set parameter maps used by all models !first allocate memory CALL NewGrid (ksat, soilTypeMap) CALL NewGrid (thetar, soilTypeMap) CALL NewGrid (thetas, soilTypeMap) CALL NewGrid (wiltingPoint, soilTypeMap) CALL NewGrid (fieldCapacity, soilTypeMap) CALL NewGrid (psdi, soilTypeMap) !then assigh parameters DO i = 1, soilTypeMap % idim DO j = 1, soilTypeMap % jdim IF (soilTypeMap % mat (i,j) /= soilTypeMap % nodata) THEN id = soilTypeMap % mat (i,j) ksat % mat (i,j) = soils (id) % ksat thetar % mat (i,j) = soils (id) % thetar thetas % mat (i,j) = soils (id) % thetas wiltingPoint % mat (i,j) = soils (id) % wp fieldCapacity % mat (i,j) = soils (id) % fc psdi % mat (i,j) = soils (id) % psdi END IF END DO END DO IF (model == SCS_CN) THEN !read supplementary parameters required by Curve Number !first allocate memory CALL NewGrid (curveNumber, soilTypeMap) CALL NewGrid (abstractionRatio, soilTypeMap) CALL NewGrid (storativity, soilTypeMap) !then assign parameters DO i = 1, soilTypeMap % idim DO j = 1, soilTypeMap % jdim IF (soilTypeMap % mat (i,j) /= soilTypeMap % nodata) THEN id = soilTypeMap % mat (i,j) curveNumber % mat (i,j) = soils (id) % cn abstractionRatio % mat (i,j) = soils (id) % c storativity % mat (i,j) = soils (id) % s0 END IF END DO END DO END IF IF (model == PHILIPEQ) THEN !read supplementary parameters required by Philips !first allocate memory CALL NewGrid (psic, soilTypeMap) !then assigh parameters DO i = 1, soilTypeMap % idim DO j = 1, soilTypeMap % jdim IF (soilTypeMap % mat (i,j) /= soilTypeMap % nodata) THEN id = soilTypeMap % mat (i,j) psic % mat (i,j) = soils (id) % psic END IF END DO END DO END IF IF (model == GREEN_AMPT) THEN !read supplementary parameters required by Green Ampt !first allocate memory CALL NewGrid (phy, soilTypeMap) !then assigh parameters DO i = 1, soilTypeMap % idim DO j = 1, soilTypeMap % jdim IF (soilTypeMap % mat (i,j) /= soilTypeMap % nodata) THEN id = soilTypeMap % mat (i,j) phy % mat (i,j) = soils (id) % phy END IF END DO END DO END IF IF (model == ROSS_BC) THEN !read supplementary parameters required by Ross Brooks and Corey !first allocate memory CALL NewGrid (psic, soilTypeMap) !then assigh parameters DO i = 1, soilTypeMap % idim DO j = 1, soilTypeMap % jdim IF (soilTypeMap % mat (i,j) /= soilTypeMap % nodata) THEN id = soilTypeMap % mat (i,j) psic % mat (i,j) = soils (id) % psic END IF END DO END DO END IF IF (model == ROSS_VG) THEN !read supplementary parameters required by Ross Van Genuchten !first allocate memory CALL NewGrid (psic, soilTypeMap) CALL NewGrid (nvg, soilTypeMap) CALL NewGrid (mvg, soilTypeMap) CALL NewGrid (ptort, soilTypeMap) CALL NewGrid (ksatMatrix, soilTypeMap) !then assigh parameters DO i = 1, soilTypeMap % idim DO j = 1, soilTypeMap % jdim IF (soilTypeMap % mat (i,j) /= soilTypeMap % nodata) THEN id = soilTypeMap % mat (i,j) psic % mat (i,j) = soils (id) % psic nvg % mat (i,j) = soils (id) % n mvg % mat (i,j) = soils (id) % m mvg % mat (i,j) = soils (id) % m ksatMatrix % mat (i,j) = soils (id) % kx END IF END DO END DO END IF RETURN END SUBROUTINE SetParametersFromDB !============================================================================== !| Description: ! set parameter maps from separate files SUBROUTINE SetParametersFromFile & ! (iniDB, model) IMPLICIT NONE ! Arguments with intent(in): TYPE (IniList), INTENT(IN) :: iniDB INTEGER (KIND = short), INTENT(IN) :: model !infiltration model !Local declaration: !------------end of declaration------------------------------------------------ !Set parameter maps used by all models !Saturated Conductivity IF (SectionIsPresent('conductivity', iniDB)) THEN CALL GridByIni (iniDB, ksat, section = 'conductivity') CALL Catch ('info', 'SoilBalance: ', 'loading saturated conductivity from file: ', & argument = IniReadString('file', iniDB, section = 'conductivity')) IF ( .NOT. CRSisEqual (mask = mask, grid = ksat, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in conductivity map' ) END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing conductivity section in configuration file' ) END IF !Saturated water content IF (SectionIsPresent('saturated-water-content', iniDB)) THEN CALL GridByIni (iniDB, thetas, section = 'saturated-water-content') CALL Catch ('info', 'SoilBalance: ', 'loading saturated water content from file: ', & argument = IniReadString('file', iniDB, section = 'saturated-water-content')) IF ( .NOT. CRSisEqual (mask = mask, grid = thetas, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in saturated-water-content' ) END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing saturated-water-content section in configuration file' ) END IF !Residual water content IF (SectionIsPresent('residual-water-content', iniDB)) THEN CALL GridByIni (iniDB, thetar, section = 'residual-water-content') CALL Catch ('info', 'SoilrBalance: ', 'loading residual water content from file: ', & argument = IniReadString('file', iniDB, section = 'residual-water-content')) IF ( .NOT. CRSisEqual (mask = mask, grid = thetar, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in residual-water-content' ) END IF ELSE CALL Catch ('error', 'SoilWaterBalance: ', & 'missing residual-water-content section in configuration file' ) END IF !Wilting Point IF (SectionIsPresent('wilting-point', iniDB)) THEN CALL GridByIni (iniDB, wiltingPoint, section = 'wilting-point') CALL Catch ('info', 'SoilBalance: ', 'loading wilting point from file: ', & argument = IniReadString('file', iniDB, section = 'wilting-point')) IF ( .NOT. CRSisEqual (mask = mask, grid = wiltingPoint, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in wilting-point' ) END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing wilting-point section in configuration file' ) END IF !Field Capacity IF (SectionIsPresent('field-capacity', iniDB)) THEN CALL GridByIni (iniDB, fieldCapacity, section = 'field-capacity') CALL Catch ('info', 'SoilBalance: ', 'loading field capacity from file: ', & argument = IniReadString('file', iniDB, section = 'field-capacity')) IF ( .NOT. CRSisEqual (mask = mask, grid = fieldCapacity, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in field-capacity' ) END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing field-capacity section in configuration file' ) END IF !Pore size distribution index IF (SectionIsPresent('pore-size-index', iniDB)) THEN CALL GridByIni (iniDB, psdi, section = 'pore-size-index') CALL Catch ('info', 'SoilBalance: ', 'loading pore size index from file: ', & argument = IniReadString('file', iniDB, section = 'pore-size-index')) IF ( .NOT. CRSisEqual (mask = mask, grid = psdi, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in pore-size-index') END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing pore-size-idex section in configuration file' ) END IF !bubbling pressure, air entry value IF (SectionIsPresent('bubble-pressure', iniDB)) THEN CALL GridByIni (iniDB, psic, section = 'bubble-pressure') CALL Catch ('info', 'SoilBalance: ', 'loading bubbling pressure from file: ', & argument = IniReadString('file', iniDB, section = 'bubble-pressure')) IF ( .NOT. CRSisEqual (mask = mask, grid = psic, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in bubbling pressure') END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing bubble-pressure section in configuration file' ) END IF IF (model == SCS_CN) THEN !read supplementary parameters required by Curve Number !Curve Number IF (SectionIsPresent('curve-number', iniDB)) THEN CALL GridByIni (iniDB, curveNumber, section = 'curve-number') CALL Catch ('info', 'SoilBalance: ', 'loading curve number from file: ', & argument = IniReadString('file', iniDB, section = 'curve-number')) IF ( .NOT. CRSisEqual (mask = mask, grid = curveNumber, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in curve number') END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing curve-number section in configuration file' ) END IF !Initial abstraction ratio IF (SectionIsPresent('abstraction-ratio', iniDB)) THEN CALL GridByIni (iniDB, abstractionRatio, section = 'abstraction-ratio') CALL Catch ('info', 'SoilBalance: ', 'loading initial abstraction ratio from file: ', & argument = IniReadString('file', iniDB, section = 'abstraction-ratio')) IF ( .NOT. CRSisEqual (mask = mask, grid = abstractionRatio, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in initial abstraction ratio') END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing abstraction-ratio section in configuration file' ) END IF !SCS-CN storativity IF (SectionIsPresent('storativity', iniDB)) THEN CALL GridByIni (iniDB, storativity, section = 'storativity') CALL Catch ('info', 'SoilBalance: ', 'loading storativity from file: ', & argument = IniReadString('file', iniDB, section = 'storativity')) IF ( .NOT. CRSisEqual (mask = mask, grid = storativity, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in storativity') END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing storativity section in configuration file' ) END IF END IF !IF (model == PHILIPEQ) THEN !read supplementary parameters required by Philips ! ! !bubbling pressure, air entry value ! IF (SectionIsPresent('bubble-pressure', iniDB)) THEN ! CALL GridByIni (iniDB, psic, section = 'bubble-pressure') ! CALL Catch ('info', 'SoilBalance: ', 'loading bubbling pressure from file: ', & ! argument = IniReadString('file', iniDB, section = 'bubble-pressure')) ! IF ( .NOT. CRSisEqual (mask = mask, grid = psic, checkCells = .TRUE.) ) THEN ! CALL Catch ('error', 'SoilBalance', & ! 'wrong spatial reference in bubbling pressure') ! END IF ! ELSE ! CALL Catch ('error', 'SoilBalance: ', & ! 'missing bubble-pressure section in configuration file' ) ! END IF ! !END IF IF (model == GREEN_AMPT) THEN !read supplementary parameters required by Green Ampt !wetting front soil suction head IF (SectionIsPresent('front-suction-head', iniDB)) THEN CALL GridByIni (iniDB, phy, section = 'front-suction-head') CALL Catch ('info', 'SoilBalance: ', 'loading wetting front suction head from file: ', & argument = IniReadString('file', iniDB, section = 'front-suction-head')) IF ( .NOT. CRSisEqual (mask = mask, grid = phy, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in wetting front suction head') END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing front-suction-head section in configuration file' ) END IF END IF IF (model == ROSS_BC) THEN !read supplementary parameters required by Ross Brooks and Corey !bubbling pressure, air entry value IF (SectionIsPresent('bubble-pressure', iniDB)) THEN CALL GridByIni (iniDB, psic, section = 'bubble-pressure') CALL Catch ('info', 'SoilBalance: ', 'loading bubbling pressure from file: ', & argument = IniReadString('file', iniDB, section = 'bubble-pressure')) IF ( .NOT. CRSisEqual (mask = mask, grid = psic, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in bubbling pressure') END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing bubble-pressure section in configuration file' ) END IF END IF IF (model == ROSS_VG) THEN !read supplementary parameters required by Ross Van Genuchten !bubbling pressure, air entry value IF (SectionIsPresent('bubble-pressure', iniDB)) THEN CALL GridByIni (iniDB, psic, section = 'bubble-pressure') CALL Catch ('info', 'SoilBalance: ', 'loading bubbling pressure from file: ', & argument = IniReadString('file', iniDB, section = 'bubble-pressure')) IF ( .NOT. CRSisEqual (mask = mask, grid = psic, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in bubbling pressure') END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing bubble-pressure section in configuration file' ) END IF !n shape parameter for Van Genuchten SWRC IF (SectionIsPresent('n-van-genuchten', iniDB)) THEN CALL GridByIni (iniDB, nvg, section = 'n-van-genuchten') CALL Catch ('info', 'SoilBalance: ', 'loading n shape parameter from file: ', & argument = IniReadString('file', iniDB, section = 'n-van-genuchten')) IF ( .NOT. CRSisEqual (mask = mask, grid = nvg, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in n shape parameter') END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing n-van-genuchten section in configuration file' ) END IF !m shape parameter for Van Genuchten SWRC IF (SectionIsPresent('m-van-genuchten', iniDB)) THEN CALL GridByIni (iniDB, mvg, section = 'm-van-genuchten') CALL Catch ('info', 'SoilBalance: ', 'loading m shape parameter from file: ', & argument = IniReadString('file', iniDB, section = 'm-van-genuchten')) IF ( .NOT. CRSisEqual (mask = mask, grid = mvg, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in m shape parameter') END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing m-van-genuchten section in configuration file' ) END IF !tortuosity index IF (SectionIsPresent('tortuosity-index', iniDB)) THEN CALL GridByIni (iniDB, ptort, section = 'tortuosity-index') CALL Catch ('info', 'SoilBalance: ', 'loading tortuosity index from file: ', & argument = IniReadString('file', iniDB, section = 'tortuosity-index')) IF ( .NOT. CRSisEqual (mask = mask, grid = ptort, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in tortuosity index') END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing tortuosity-index section in configuration file' ) END IF !saturated conductivity of soil "matrix" IF (SectionIsPresent('conductivity-matrix', iniDB)) THEN CALL GridByIni (iniDB, ksatMatrix, section = 'conductivity-matrix') CALL Catch ('info', 'SoilBalance: ', 'loading soil matrix conductivity from file: ', & argument = IniReadString('file', iniDB, section = 'conductivity-matrix')) IF ( .NOT. CRSisEqual (mask = mask, grid = ksatMatrix, checkCells = .TRUE.) ) THEN CALL Catch ('error', 'SoilBalance', & 'wrong spatial reference in soil matrix conductivity') END IF ELSE CALL Catch ('error', 'SoilBalance: ', & 'missing conductivity-matrix section in configuration file' ) END IF END IF RETURN END SUBROUTINE SetParametersFromFile !============================================================================== !| calculates the actual rate of infiltration (m/s) according to ! Curve Number model modified for continuous simulation ! ! References: ! ! Ravazzani, G., Mancini, M., Giudici, I., & Amadio, P.. (2007). ! Effects of soil moisture parameterization on a real- time flood ! forecasting system based on rainfall thresholds. ! IAHS publication, 313, 407–416. ! ! Rabuffetti, D., Ravazzani, G., Corbari, C., & Mancini, M.. (2008). ! Verification of operational quantitative discharge forecast (QDF) ! for a regional warning system – the AMPHORE case studies in the ! upper Po river. Natural hazards and earth system sciences, 8, 161–173. ! ! Ravazzani, G., Amengual, A., Ceppi, A., Homar, V., Romero, R., ! Lombardi, G., & Mancini, M.. (2016). Potentialities of ensemble ! strategies for flood forecasting over the Milano urban area. ! Journal of hydrology, 539, 237-253. ! FUNCTION SCScurveNumber & ! (rain, raincum, c, s, dt, runoff) & ! RESULT (inf) IMPLICIT NONE !Arguments with intent in REAL (KIND = float), INTENT(IN) :: rain !!rainfall rate (m/s) REAL (KIND = float), INTENT(IN) :: c !!initial abstraction ratio (-) REAL (KIND = float), INTENT(IN) :: s !!soil retention capacity (mm) INTEGER (KIND = short), INTENT(IN) :: dt !!time step (s) !Arguments with intent inout: REAL (KIND = float), INTENT(INOUT) :: raincum !!cumulated rainfall from start of storm (mm) !! is used and updated to be ready for the !! following step !Arguments with intent out REAL (KIND = double), INTENT(OUT) :: runoff !!runoff rate (m/s) !local declarations: REAL (KIND = float) :: inf !!infiltration rate (m/s) REAL (KIND = float) :: raincump !!cumulative precipitation of previous time step (mm) REAL (KIND = float) :: runoffp !!cumulative runoff of previous time step (mm) !-------------------------end of declarations---------------------------------- !if retention capacity = 0 (soil is saturated) ! rainfall is transformed to runoff IF (s == 0.) THEN raincum = raincum + rain * 1000. * dt !update cumulative rainfall runoff = rain inf = 0. RETURN !no need to continue END IF !calculate runoff and infiltration rate !update cumulative precipitation raincump = raincum !save cumulated precipitation amount of previous time step raincum = raincum + rain * dt * 1000. !(mm) !runoff at current time IF(raincum >= c*s) THEN runoff = ((raincum - c*s )**2.) / (raincum + (1.-c) * s) ELSE runoff = 0. END IF !runoff at previous time IF(raincump >= c*S) THEN runoffp = ((raincump - c*S )**2.) / (raincump + (1.-c) * s) ELSE runoffp = 0. END IF !actual runoff in m/s runoff = (runoff - runoffp) / 1000. / dt !actual infiltration rate in m/s inf = rain - runoff RETURN END FUNCTION SCScurveNumber !============================================================================== !| compute actual soil retention capacity S of the SCS-CN method ! given soil saturation SUBROUTINE Sat2scn & ! (cn2, s0, soilsat, scn) IMPLICIT NONE !arguments with intent in: REAL (KIND = float), INTENT(IN) :: cn2 !!curve number for mean soil moisture REAL (KIND = float), INTENT(IN) :: s0 !!storativity (mm) REAL (KIND = float), INTENT(IN) :: soilsat !!soil saturation !arguments with intent out: REAL (KIND = float), INTENT(OUT) :: scn !!soil retention capacity [mm] !local declarations: REAL (KIND = float) :: cn1, cn3, s1, s2, s3 !-------------------------end of declarations---------------------------------- !compute cn1 and cn3 from cn2 cn1 = cn2 - (20. * (100. - cn2) ) / & (100. - cn2 + EXP(2.533 - .0636 * (100. - cn2) ) ) IF (cn1 < 0.4 * CN2) cn1 = .4 * cn2 cn3 = cn2 * EXP( .00673 * (100. - cn2) ) !compute s1, s2, and s3 s1 = s0 * (100. / cn1 - 1.) s2 = s0 * (100. / cn2 - 1.) s3 = s0 * (100. / cn3 - 1.) !compute actual S scn = s1 - soilsat * (s1 - s3) RETURN END SUBROUTINE sat2scn !============================================================================== !| calculates the actual rate of infiltration (m/s) according to ! Philip's equation. Use time compression approximation. ! ! References: ! ! Philip, J. R. 1954. An infiltration equation with physical ! significance. Soil Science, 77: 153-157. ! ! Milly, P. C. D., An event-based simulation model of moisture and ! energy fluxes at a bare soil surface, ! Water Resour. Res., 22, 1680-! 692, 1986 ! ! Sivapalan, M., Beven, K., and Wood, E. F. (1987), On hydrologic similarity: ! 2 . A scaled model of storm runoff production, Water Resour. ! Res., 23( 12), 2266– 2278, doi:10.1029/WR023i012p02266. ! FUNCTION Philip & ! (rain, psic, ksat, theta, thetas, thetar, psdi, itheta, dt, cuminf) & ! RESULT (inf) IMPLICIT NONE !Arguments with intent in REAL (KIND = float), INTENT(IN) :: rain !!rainfall rate (m/s) REAL (KIND = float), INTENT(IN) :: psic !!bubbling pressure (m) REAL (KIND = float), INTENT(IN) :: ksat !!saturated hydraulic conductivity (m/s) REAL (KIND = float), INTENT(IN) :: theta !!volumetric water content (m3/m3) REAL (KIND = float), INTENT(IN) :: thetas !!saturated volumetric water content (m3/m3) REAL (KIND = float), INTENT(IN) :: thetar !!residual volumetric water content (m3/m3) REAL (KIND = float), INTENT(IN) :: psdi !!Brooks & Corey pore size distribution index (-) INTEGER (KIND = short), INTENT(IN) :: dt !!time step (s) REAL (KIND = float), INTENT(IN) :: itheta !!initial soil moisture !Arguments with intent inout: REAL (KIND = float), INTENT(INOUT) :: cuminf !!cumulative infiltration (m) !local declarations: REAL (KIND = float) :: inf !!infiltration rate (m/s) REAL (KIND = float) :: sorp !!sorptivity REAL (KIND = float) :: cc = 0. !!gravity term in Philip's infiltration equation REAL (KIND = float) :: deltrz !! difference between soil moisture at beginning !! of storm event and residual soil moisture REAL (KIND = float) :: bcgamm !!2.0 + 3.0 * psdi REAL (KIND = float) :: infcap !!infiltration capacity (m/s) !-------------------------end of declarations---------------------------------- ! Sivapalan et al. (1987) bcgamm = 2.0 + 3.0 * psdi sorp = (((2. * ksat *( (thetas-itheta)**2.) * psic ) / & (thetas-thetar))*((1./(bcgamm + 0.5 * psdi - 1.)) + & ((thetas-thetar)/ (thetas-itheta) ) ) ) ** 0.5 deltrz = itheta - thetar IF (deltrz <= 0.) deltrz = 0. cc = 0.5 * (1. + ( (deltrz / (thetas - thetar))**(bcgamm / psdi) ) ) !If soil is saturated then set infiltration to zero IF (theta >= thetas) THEN inf = 0. !If surface is unsaturated then calculate infiltration ELSE !If first step with infiltration then all precipitation is !infiltrated to avoid division by zero IF (cuminf == 0.) THEN inf = rain !calculate infiltration capacity as a function of cumulative ! infiltration for all other time steps of storm (Milly, 1986) ELSE infcap = cc * ksat * (1. + (1./ ((( 1. + (( 4. * cc * ksat * cuminf ) / & (sorp**2.)))**0.5) - 1.))) !Take the actual infiltration rate as the minimum of the ! precipitation rate or the infiltration capacity. inf = MIN (infcap,rain) END IF !update cumulative infiltration cuminf = cuminf + inf * dt END IF RETURN END FUNCTION Philip !============================================================================== !| calculates the actual rate of infiltration (m/s) according to ! Green-Ampt equation for unsteady rainfall. ! ! References: ! ! Green, WH., and Ampt, GA., 1911. Studies on soil physics I. ! Flow of air and water through soils. J. Agric. Sci. 4: 1- 24. ! ! Chow, V., Maidment, D., Mays, L. (1988) Applied Hydrology, ! Surface water, pp. 142-145, McGraw-Hill ! FUNCTION GreenAmpt & ! (storm, rain, ksat, theta, thetas, thetar, phy, itheta, dt, cuminf) & ! RESULT (inf) IMPLICIT NONE !Arguments with intent in INTEGER (KIND = short), INTENT(IN) :: storm !!when = 1 first steo of storm event REAL (KIND = float), INTENT(IN) :: rain !!rainfall rate (m/s) REAL (KIND = float), INTENT(IN) :: ksat !!saturated hydraulic conductivity (m/s) REAL (KIND = float), INTENT(IN) :: theta !!volumetric water content (m3/m3) REAL (KIND = float), INTENT(IN) :: thetas !!saturated volumetric water content (m3/m3) REAL (KIND = float), INTENT(IN) :: thetar !!residual volumetric water content (m3/m3) REAL (KIND = float), INTENT(IN) :: phy !!suction head across the wetting front (m) INTEGER (KIND = short), INTENT(IN) :: dt !!time step (s) REAL (KIND = float), INTENT(IN) :: itheta !!initial soil moisture !Arguments with intent inout: REAL (KIND = float), INTENT(INOUT) :: cuminf !!cumulative infiltration (m) !local declarations: REAL (KIND = float) :: inf !!infiltration rate (m/s) REAL (KIND = float) :: deltrz !! difference between soil moisture at beginning !! of storm event and residual soil moisture REAL (KIND = float) :: test !!test value for the cumulative infiltration (m) REAL (KIND = float) :: ftest !!test value for the cumulative infiltration (m) INTEGER (KIND = short) :: i !loop INTEGER (KIND = short) :: maxiter = 100 !maximum number of iteration for ! computing cumulative infiltration REAL (KIND = float) :: tol = 0.00001 !tolerance to compute cumulative infiltration (m) REAL (KIND = float) :: deltatfirst !!for ponding time (case 3) REAL (KIND = float) :: Fponding !!cumulative infiltration at ponding (case 3) REAL (KIND = float) :: deltatpond !! new deltat calculated for ponding (case 3) !-------------------------end of declarations---------------------------------- !if this is the first step of storm event: ! initialize variables IF ( storm == 1) THEN deltrz = thetas - theta IF (deltrz <= 0.) THEN deltrz = 0. END IF !assume all precipitation is infiltrated cuminf = rain * dt inf = rain RETURN END IF !If soil is saturated then set infiltration to zero IF (theta >= thetas) THEN inf = 0. RETURN !If surface is unsaturated then calculate infiltration ELSE IF (storm == 2) THEN !storm is running !calculate potential infiltration rate at the beginning of the interval !from the known value of cumulative infiltration (eq 5.4.1) inf = ksat * (phy * (thetas-itheta) / cuminf + 1.) !compare potential infiltration to rainfall rate IF (inf <= rain) THEN !ponding occurs throughout the interval (case 1) test = Ksat*dt !first guess for cumulative infiltration DO i = 1, maxiter IF (i == maxiter) THEN CALL Catch ('warning', 'Infiltration', 'maximum number of iterations & reached while updating cumulative infiltration & with green-ampt case 1' ) END IF ftest = cuminf + ksat*dt + (phy*(thetas-itheta))* & LOG ((test+(phy*(thetas-itheta)))/(cuminf+(phy*(thetas-itheta)))) IF (ABS(ftest-test) <= tol) THEN cuminf = ftest !compute infiltration rate from cumulative infiltration inf = ksat * (phy * (thetas-itheta) / cuminf + 1.) IF (inf > rain) inf = rain EXIT ELSE test = ftest END IF END DO ELSE !no ponding at the beginning of the interval !calculate tentative values Assuming that all the rain !water is penetrated into the soil test = cuminf + rain * dt inf = ksat * (phy * (thetas-itheta) / test + 1.) IF (inf <= rain) THEN !ponding occurs during the interval (case 3) Fponding = ksat * phy * (thetas-itheta) / (rain - ksat) deltatfirst = (Fponding - cuminf) / rain deltatpond = dt - deltatfirst !compute cumulative infiltration by substituting cuminf = Fponding !and dt = deltatpond test = Fponding !Ksat*dt !first guess for cumulative infiltration DO i = 1, maxiter IF (i == maxiter) THEN CALL Catch ('warning', 'Infiltration', 'maximum number of iterations & reached while updating cumulative infiltration & with green-ampt case 3' ) END IF ftest = Fponding + ksat*deltatpond + (phy*(thetas-itheta))* & LOG ((test+(phy*(thetas-itheta)))/(Fponding+(phy*(thetas-itheta)))) IF (ABS(ftest-test) <= tol) THEN cuminf = ftest !compute infiltration rate from cumulative infiltration inf = ksat * (phy * (thetas-itheta) / cuminf + 1.) IF (inf > rain) inf = rain EXIT ELSE test = ftest END IF END DO ELSE !no ponding throghout the interval (case 2) cuminf = test inf = rain END IF END IF ELSE inf = 0. END IF END IF END FUNCTION GreenAmpt END MODULE Infiltration